package org.lizar.ioc;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.lizar.Web;
import org.lizar.config.Config;
import org.lizar.controller.Event;
import org.lizar.exception.UnknownCellKey;
import org.lizar.ioc.module.Module;
import org.lizar.json.JList;
import org.lizar.log.Log;
import org.lizar.log.Logger;
import org.lizar.util.ClassUtils;



/**
 * 
 * This is Lizar Engine * 
 * 
 * */
public class Container {
    
	private static Log log=Logger.newInstance(Container.class);
	
	
	
    private static Map<String,Cell> cells;
    
	public Container(){
		cells=new HashMap<String,Cell>();
	}
	
	
	/**
	 * check and initialize all cells by calling cell's init_property method.
	 */
	public void check_cells(){
		
		
		
		 JList ioc_package=Config.xpath_list("container_info.ioc_package");
	     if(ioc_package==null){
	        	log.warn("Lizar IOC can not detect any package scanning settings, please check lizar.json of container_info.ioc_package settings");
	     }
	        
	     Set<Class<Cell>> cells_set = new LinkedHashSet<Class<Cell>>();
	     for(Object o:ioc_package){
	    	 	log.info("search package:"+o);
	        	 ClassUtils.getClasses(o.toString(),cells_set);
	     }
	        
	     if(cells_set.size()==0){
	        	log.warn("Lizar IOC can not detect any Cells, please check lizar.json of container_info.ioc_package settings");
	     }
		 Cell b;
		 List<Cell> start_list=new ArrayList<Cell>(cells_set.size());
		 for(Class<Cell> c:cells_set){
			try{
				b=(Cell)c.newInstance();
			}catch(Exception e){
				log.warn("Cell "+c.getName()+" can not be created");
				continue;
			}
			start_list.add(b);
			cells.put(c.getName(), b);
			if(b instanceof Event)Web.events.put(c.getName(), (Event)b);
			else if(b instanceof Module)Web.modules.put(c.getName(), (Module)b);
			else if(b instanceof Lifecycle)Web.lifecycle_list.add((Lifecycle)b);
		 }
		 ioc_perform(start_list);
	}
	
	private void ioc_perform(List<Cell> start_list){
		Cell cell;
		boolean need_to_end=false;
		Exception ex=null;
		String class_name=null;
		log.info("Totally "+start_list.size()+" cell has been found to init.");
		while(!need_to_end){
			int s=start_list.size();
			for(int i=0;i<start_list.size();){
				cell=start_list.get(i);
				try {
					class_name=cell.getClass().getName();
					cell.init_property();
				} catch (Exception e1) {
					ex=e1;
					i++;
					log.debug("trying to init :"+class_name+"  failed, \t\t\tskip it.");
					continue;
				}
				log.debug("trying to init :"+class_name+"  \t\t\tdone.");
				start_list.remove(i);
			}
			if(start_list.size()==0||start_list.size()==s)need_to_end=true;
			if(start_list.size()>0&&need_to_end){
				log.error("Container init cell "+class_name+" init failed pls make sure init_property is only for init property of class not to use then, caused by:",ex);
			}
		}
	}
	
  
    public static Map<String,Cell> getAll(){
    	return cells;
    }
    
    
    public static <T> T get(Class<T> t){
    	Cell h=cells.get(t.getName());
    	if(h==null)throw new UnknownCellKey(t.getName());
    	return (T)h;
    }
    
    
   
  

	/**
	 * Destruction of the servlet. <br>
	 */
	public void destroy() {
		cells.clear();
    	
	}

	


	
	
	
	
	

	
	
	
	
	
	
}
